/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-11-24
 * Time: 22:30
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;

using Labb4.Pooman.Cards;

namespace Labb4.Pooman.Players
{
	/// <summary>
	/// A container class for all the players with methods for deciding the player order
	/// and apointing a winner and some operations that should be done to all players
	/// at once
	/// 
	/// Implements the Singleton design pattern
	/// </summary>
	public sealed class PlayerManager //singelton
	{
		#region members
		
		/// <summary>
		/// The one instance
		/// </summary>
		private static PlayerManager		m_Instance = new PlayerManager();
		/// <summary>
		/// All registered players
		/// </summary>
		private List<Player>				m_Players;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		private PlayerManager()
		{
			m_Players = new List<Player>();
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Adds a player to the List of Player
		/// A player can only be added once
		/// If the same player is attempted to be added more than once, a debug message is written to the output
		/// </summary>
		/// <param name="player"></param>
		public void AddPlayer(Player player)
		{
			if(!m_Players.Contains(player))
			{
				m_Players.Add(player);
			}
			else
			{
				Debug.WriteLine("A player was added more than once in the PlayerManager");
			}
		}
		
		/// <summary>
		/// This method is needed for the tests..
		/// </summary>
		/// <param name="index">The position, or index, at which to remove a player</param>
		public void RemoveAt(int index)
		{
			if(index > -1)
			{
				if(index < m_Players.Count)
				{
					m_Players.RemoveAt(index);
				}
			}
		}
		
		/// <summary>
		/// Creates the next group of players ordered in the order they are added to the
		/// member collection. The player sent as argument will be first in the swarm,
		/// and then all players are added one by one until all players in the member
		/// collection have been added.
		/// 
		/// This method does not return a new swarm. Instead it fills a swarm sent as argument,
		/// and the user of this method is responsible for how many players are allready
		/// in that swarm before this method starts adding players. In any case, the same amount
		/// of players is always added to the swarm when this method is called. This amount
		/// is the number of elements in the member collection of players.
		/// </summary>
		/// <param name="winner">The player who should be added first to the swarm</param>
		/// <param name="swarm">The swarm to which players should be added</param>
		public void GetNextSwarm(Player winner, PlayerSwarm swarm)
		{
			if(m_Players.Contains(winner))
			{
				int added = 0;
				int current = 0;
				bool startAdding = false;
				
				while(added != m_Players.Count)
				{
					if(m_Players[current] == winner)
					{
						startAdding = true;
					}
					
					if(startAdding)
					{
						if(m_Players[current].CurrentHand.Cards.Count > 0)
						{
							swarm.AddPlayer(m_Players[current]);
						}
						
						added++;
					}
					
					current++;
					
					if(current >= m_Players.Count)
					{
						current = 0;
					}
				}
			}
			else
			{
				//This has never happened
				Debug.WriteLine("The player asked to be first in the new swarm is not registered with the player manager..");
			}
		}
		
		/// <summary>
		/// Calls the method <see cref="Player.ClearAllCards">ClearAllCards</see> on all the players
		/// registered in the member collection
		/// </summary>
		public void ClearAllPlayersCards()
		{
			foreach(Player it in m_Players)
			{
				it.ClearAllCards();
			}
		}
		
		/// <summary>
		/// Sorts and graphically positions the cards on every player's current hand
		/// </summary>
		public void SortAndPositionCards()
		{
			foreach(Player it in m_Players)
			{
				it.CurrentHand.Cards.Sort();
				it.PositionCards();
			}
		}
		
		/// <summary>
		/// Attempts to find a Poo man among the players registered in the member collection
		/// </summary>
		/// <returns>The player concidered to be the Poo man, null if none matched the criteria</returns>
		public Player GetPooman()
		{
			Player pooman = null;
			int playersWithCards = 0;
			
			foreach(Player it in m_Players)
			{
				if(it.CurrentHand.Cards.Count > 0)
				{
					pooman = it;
					playersWithCards++;
				}
			}
			
			if(playersWithCards != 1)
			{
				pooman = null;
			}
			
			return pooman;
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// The one instance (get)
		/// </summary>
		public static PlayerManager Instance
		{
			get
			{
				return m_Instance;
			}
		}
		
		/// <summary>
		/// The number of players added to the member collection (get)
		/// </summary>
		public int Count
		{
			get
			{
				return m_Players.Count;
			}
		}
		
		/// <summary>
		/// The player at position [index] (get)
		/// </summary>
		public Player this[int index]
		{
			get
			{
				Player player = null;
				
				if(m_Players.Count > index)
				{
					player = m_Players[index];
				}
				
				return player;
			}
		}
		
		/// <summary>
		/// The position of the [player] (get)
		/// Note: will return -1 if the player is not found, after that the first position is called 0
		/// </summary>
		public int this[Player player]
		{
			get
			{
				int i = -1;
				
				if(m_Players.Contains(player))
				{
					i = m_Players.IndexOf(player);
				}
				
				return i;
			}
		}
		
		#endregion
	}
}
